package priv.wangy.micro.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Java反射工具
 *
 * @author Admin
 */
@Slf4j
public class ReflectUtil {

    /**
     * @param t:
     * @param k:
     * @param objectT:
     * @param objectK:
     * @author 汪颖
     * @since 2022-09-16
     **/
    public static <T, K> void addEmptyParam(Class<T> t, Class<K> k, T objectT, K objectK) {
        try {
            Field[] fields = t.getDeclaredFields();
            Field[] fieldK = k.getDeclaredFields();
            List<String> nameK = Arrays.stream(fieldK).map(Field::getName).toList();
            for (Field field : fields) {
                field.setAccessible(true);
                Object value = field.get(objectT);
                if (value != null && nameK.contains(field.getName())) {
                    Field appField = k.getDeclaredField(field.getName());
                    appField.setAccessible(true);
                    appField.set(objectK, value);
                }
            }
        } catch (IllegalAccessException | NoSuchFieldException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 此方法要求，k是t的子集
     *
     * @param t:
     * @param k:
     * @param objectT:
     * @param objectK:
     * @author 汪颖
     * @since 2022-09-16
     **/
    public static <T, K> void addEmptyParamTHasOther(Class<T> t, Class<K> k, T objectT, K objectK) {
        try {
            Field[] fields = k.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                Object value = field.get(objectT);
                if (value != null) {
                    Field appField = k.getDeclaredField(field.getName());
                    appField.setAccessible(true);
                    appField.set(objectK, value);
                }
            }
        } catch (IllegalAccessException | NoSuchFieldException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 检查对象属性是否全为空
     * 有一个非空属性即返回false
     */
    public static <T> boolean isAllFieldsNull(T t, Class<T> clazz) {
        try {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if (Objects.nonNull(field.get(t))) {
                    return false;
                }
            }
        } catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return true;
    }

    /**
     * 检查对象属性是否全不为空
     * 有一个空属性即返回false
     */
    public static <T> boolean isAllFieldsNonNull(T t, Class<T> clazz) {
        try {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if (Objects.isNull(field.get(t))) {
                    return false;
                }
            }
        } catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return true;
    }

    /**
     * 检查对象目标属性中是否有空属性
     * 存在任一为空的目标属性即返回true
     */
    public static <T> boolean isAnyFieldsNull(T t, Class<T> clazz, String... names) {
        try {
            for (String name : names) {
                Field field = clazz.getDeclaredField(name);
                field.setAccessible(true);
                Object obj = field.get(t);
                if (Objects.isNull(field.get(t))) {
                    return true;
                }
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return false;
    }

    /**
     * 检查对象目标属性中是否有非空属性
     * 存在任一非空的目标属性即返回true
     */
    public static <T> boolean isAnyFieldsNonNull(T t, Class<T> clazz, String... names) {
        try {
            for (String name : names) {
                Field field = clazz.getDeclaredField(name);
                field.setAccessible(true);
                if (Objects.nonNull(field.get(t))) {
                    return true;
                }
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return false;
    }

    /**
     * 检查对象目标属性中是否有空属性
     * 存在任一为空的目标属性即返回true
     */
    public static <T> boolean isAnyFieldsBlank(T t, Class<T> clazz, String... names) {
        try {
            for (String name : names) {
                Field field = clazz.getDeclaredField(name);
                field.setAccessible(true);
                Object obj = field.get(t);
                if (Objects.isNull(obj)) {
                    return true;
                }
                if (obj instanceof String && ((String) obj).isEmpty()) {
                    return true;
                }
                if (obj instanceof List && ((List<?>) obj).isEmpty()) {
                    return true;
                }
                if (obj instanceof Integer && (Integer) obj == 0) {
                    return true;
                }
                if (obj instanceof Long && (Long) obj == 0) {
                    return true;
                }
                if (obj instanceof Double && (Double) obj == 0) {
                    return true;
                }
                if (obj instanceof Short && (Short) obj == 0) {
                    return true;
                }
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return false;
    }

    public static <T> boolean isAllFieldsBlank(T t, Class<T> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        return isAnyFieldsBlank(t, clazz, Arrays.stream(fields).map(Field::getName).toArray(String[]::new));
    }

    /**
     * 检查对象目标属性中是否有非空属性
     * 存在任一非空的目标属性即返回true
     */
    public static <T> boolean isAnyFieldsNotBlank(T t, Class<T> clazz, String... names) {
        try {
            for (String name : names) {
                Field field = clazz.getDeclaredField(name);
                field.setAccessible(true);
                Object obj = field.get(t);
                if (Objects.nonNull(obj)) {
                    if (obj instanceof String && ((String) obj).isEmpty()) {
                        continue;
                    }
                    if (obj instanceof List && ((List<?>) obj).isEmpty()) {
                        continue;
                    }
                    if (obj instanceof Integer && (Integer) obj == 0) {
                        continue;
                    }
                    if (obj instanceof Long && (Long) obj == 0) {
                        continue;
                    }
                    if (obj instanceof Double && (Double) obj == 0) {
                        continue;
                    }
                    if (obj instanceof Short && (Short) obj == 0) {
                        continue;
                    }
                    return true;
                }
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return false;
    }

    /**
     * 检查对象数值参数是否全为自然数
     */
    public static <T> boolean isAllNumbersNatural(T t, Class<T> clazz) {
        try {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                Object obj = field.get(t);
                if (Objects.isNull(obj)) {
                    continue;
                }
                if (obj instanceof Integer && (Integer) obj <= 0) {
                    return false;
                }
                if (obj instanceof Long) {
                    String str = String.valueOf(obj);
                    if (!StringUtils.isNumeric(str)) {
                        return false;
                    }
                }
                if (obj instanceof Double) {
                    String str = String.valueOf(obj);
                    if (!StringUtils.isNumeric(str)) {
                        return false;
                    }
                }
                if (obj instanceof Short) {
                    String str = String.valueOf(obj);
                    if (!StringUtils.isNumeric(str)) {
                        return false;
                    }
                }
            }
        } catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return true;
    }

    /**
     * 获取对象中第一个空属性
     * 返回第一个空属性名称
     */
    public static <T> String firstNullField(T t, Class<T> clazz) {
        try {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if (Objects.isNull(field.get(t))) {
                    return field.getName();
                }
            }
        } catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 获取对象中第一个空属性
     * 返回第一个空属性名称
     */
    public static <T> String firstNullField(T t, Class<T> clazz, String... names) {
        try {
            for (String name : names) {
                Field field = clazz.getDeclaredField(name);
                field.setAccessible(true);
                if (Objects.isNull(field.get(t))) {
                    return name;
                }
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 获取对象中第一个空属性
     * 返回第一个空属性名称
     */
    public static <T> String firstBlankField(T t, Class<T> clazz) {
        try {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                Object obj = field.get(t);
                if (Objects.isNull(obj)) {
                    return field.getName();
                }
                if (obj instanceof String && ((String) obj).isEmpty()) {
                    return field.getName();
                }
                if (obj instanceof List && ((List<?>) obj).isEmpty()) {
                    return field.getName();
                }
                if (obj instanceof Integer && (Integer) obj == 0) {
                    return field.getName();
                }
                if (obj instanceof Long && (Long) obj == 0) {
                    return field.getName();
                }
                if (obj instanceof Double && (Double) obj == 0) {
                    return field.getName();
                }
                if (obj instanceof Short && (Short) obj == 0) {
                    return field.getName();
                }
            }
        } catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 获取对象中第一个空属性
     * 返回第一个空属性名称
     */
    public static <T> String firstBlankField(T t, Class<T> clazz, String... names) {
        try {
            for (String name : names) {
                Field field = clazz.getDeclaredField(name);
                field.setAccessible(true);
                Object obj = field.get(t);
                if (Objects.isNull(obj)) {
                    return name;
                }
                if (obj instanceof String && ((String) obj).isEmpty()) {
                    return name;
                }
                if (obj instanceof List && ((List<?>) obj).isEmpty()) {
                    return name;
                }
                if (obj instanceof Integer && (Integer) obj == 0) {
                    return name;
                }
                if (obj instanceof Long && (Long) obj == 0) {
                    return name;
                }
                if (obj instanceof Double && (Double) obj == 0) {
                    return name;
                }
                if (obj instanceof Short && (Short) obj == 0) {
                    return name;
                }
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    public static <T> boolean isField(Class<T> clazz, String name) {
        return Arrays.stream(clazz.getDeclaredFields()).anyMatch(field -> Objects.equals(field.getName(), name));
    }

    public static List<Field> getFields(Class<?> clazz) {
        List<Field> fields = Arrays.stream(clazz.getDeclaredFields()).collect(Collectors.toList());
        Class<?> superClazz = clazz.getSuperclass();
        if (!superClazz.equals(Object.class)) {
            fields.addAll(getFields(superClazz));
        }
        return fields;
    }

    public static String getter(Object obj, String fieldName, Class<?> clazz) {
        try {
            Field field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            if (field.getType().equals(String.class)) {
                return (String) field.get(obj);
            }
        } catch (NoSuchFieldException e) {
            Class<?> superClazz = clazz.getSuperclass();
            if (!superClazz.equals(Object.class)) {
                return getter(obj, fieldName, superClazz);
            }
        } catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    public static void setter(Object obj, String fieldName, String value, Class<?> clazz) {
        try {
            Field field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            if (field.getType().equals(String.class)) {
                field.set(obj, value);
            }
        } catch (NoSuchFieldException e) {
            Class<?> superClazz = clazz.getSuperclass();
            if (!superClazz.equals(Object.class)) {
                setter(obj, fieldName, value, superClazz);
            }
        } catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
    }
}
